<!DOCTYPE html>
<html>
  <head>
  <meta http-equiv="content-type" content="text/html; charset=utf-8">
  <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport">
  <meta name="description" content="JinYan&#39;s blog">
  <meta name="keyword" content="hexo-theme, vuejs">
  
    <link rel="shortcut icon" href="/blog/css/images/logo.jpg">
  
  <title>
    
      openvpn-install.sh | SanYuanEmpire
    
  </title>
  <link href="//cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
  <link href="//cdn.bootcss.com/nprogress/0.2.0/nprogress.min.css" rel="stylesheet">
  <link href="//cdn.bootcss.com/highlight.js/9.12.0/styles/tomorrow.min.css" rel="stylesheet">
  <link rel="stylesheet" href="/blog/css/style.css">
<link rel="stylesheet" href="/blog/css/plugins/gitment.css">
  <script src="//cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
  <script src="//cdn.bootcss.com/geopattern/1.2.3/js/geopattern.min.js"></script>
  <script src="//cdn.bootcss.com/nprogress/0.2.0/nprogress.min.js"></script>
  <script src="/blog/js/qrious.js"></script>
<script src="/blog/js/gitment.js"></script>
  
  
    <!-- MathJax support START -->
    <script type="text/x-mathjax-config">
      MathJax.Hub.Config({
        tex2jax: {
          inlineMath: [ ['$','$'], ["\\(","\\)"]  ],
          processEscapes: true,
          skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
        }
      });
    </script>

    <script type="text/x-mathjax-config">
      MathJax.Hub.Queue(function() {
        var all = MathJax.Hub.getAllJax(), i;
        for (i=0; i < all.length; i += 1) {
          all[i].SourceElement().parentNode.className += ' has-jax';
        }
      });
    </script>
    <script type="text/javascript" src="//cdn.bootcss.com/mathjax/2.7.1/latest.js?config=TeX-AMS-MML_HTMLorMML"></script>
    <!-- MathJax support END -->
  


</head>
<div class="wechat-share">
  <img src="/css/images/logo.jpg" />
</div>

  <body>
    <header class="header fixed-header">
  <div class="header-container">
    <a class="home-link" href="/blog/">
      <div class="logo"></div>
      <span>SanYuanEmpire</span>
    </a>
    <ul class="right-list">
      
        <li class="list-item">
          
            <a href="/blog/" class="item-link">Home</a>
          
        </li>
      
        <li class="list-item">
          
            <a href="/blog/archives/" class="item-link">Archives</a>
          
        </li>
      
    </ul>
    <div class="menu">
      <span class="icon-bar"></span>
      <span class="icon-bar"></span>
      <span class="icon-bar"></span>
    </div>
    <div class="menu-mask">
      <ul class="menu-list">
        
          <li class="menu-item">
            
              <a href="/blog/" class="menu-link">Home</a>
            
          </li>
        
          <li class="menu-item">
            
              <a href="/blog/archives/" class="menu-link">Archives</a>
            
          </li>
        
      </ul>
    </div>
  </div>
</header>

    <div id="article-banner">
  <h2>openvpn-install.sh</h2>
  <p class="post-date">2018-09-09</p>
  <div class="arrow-down">
    <a href="javascript:;"></a>
  </div>
</div>
<main class="app-body flex-box">
  <!-- Article START -->
  <article class="post-article">
    <section class="markdown-content"><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br><span class="line">358</span><br><span class="line">359</span><br><span class="line">360</span><br><span class="line">361</span><br><span class="line">362</span><br><span class="line">363</span><br><span class="line">364</span><br><span class="line">365</span><br><span class="line">366</span><br><span class="line">367</span><br><span class="line">368</span><br><span class="line">369</span><br><span class="line">370</span><br><span class="line">371</span><br><span class="line">372</span><br><span class="line">373</span><br><span class="line">374</span><br><span class="line">375</span><br><span class="line">376</span><br><span class="line">377</span><br><span class="line">378</span><br><span class="line">379</span><br><span class="line">380</span><br><span class="line">381</span><br><span class="line">382</span><br><span class="line">383</span><br><span class="line">384</span><br><span class="line">385</span><br><span class="line">386</span><br><span class="line">387</span><br><span class="line">388</span><br><span class="line">389</span><br><span class="line">390</span><br><span class="line">391</span><br><span class="line">392</span><br><span class="line">393</span><br><span class="line">394</span><br><span class="line">395</span><br><span class="line">396</span><br><span class="line">397</span><br></pre></td><td class="code"><pre><span class="line">#!/bin/bash</span><br><span class="line">#</span><br><span class="line"># https://github.com/Nyr/openvpn-install</span><br><span class="line">#</span><br><span class="line"># Copyright (c) 2013 Nyr. Released under the MIT License.</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"># Detect Debian users running the script with &quot;sh&quot; instead of bash</span><br><span class="line">if readlink /proc/$$/exe | grep -q &quot;dash&quot;; then</span><br><span class="line"> echo &quot;This script needs to be run with bash, not sh&quot;</span><br><span class="line"> exit</span><br><span class="line">fi</span><br><span class="line"></span><br><span class="line">if [[ &quot;$EUID&quot; -ne 0 ]]; then</span><br><span class="line"> echo &quot;Sorry, you need to run this as root&quot;</span><br><span class="line"> exit</span><br><span class="line">fi</span><br><span class="line"></span><br><span class="line">if [[ ! -e /dev/net/tun ]]; then</span><br><span class="line"> echo &quot;The TUN device is not available</span><br><span class="line">You need to enable TUN before running this script&quot;</span><br><span class="line"> exit</span><br><span class="line">fi</span><br><span class="line"></span><br><span class="line">if [[ -e /etc/debian_version ]]; then</span><br><span class="line"> OS=debian</span><br><span class="line"> GROUPNAME=nogroup</span><br><span class="line"> RCLOCAL=&apos;/etc/rc.local&apos;</span><br><span class="line">elif [[ -e /etc/centos-release || -e /etc/redhat-release ]]; then</span><br><span class="line"> OS=centos</span><br><span class="line"> GROUPNAME=nobody</span><br><span class="line"> RCLOCAL=&apos;/etc/rc.d/rc.local&apos;</span><br><span class="line">else</span><br><span class="line"> echo &quot;Looks like you aren&apos;t running this installer on Debian, Ubuntu or CentOS&quot;</span><br><span class="line"> exit</span><br><span class="line">fi</span><br><span class="line"></span><br><span class="line">newclient () &#123;</span><br><span class="line"> # Generates the custom client.ovpn</span><br><span class="line"> cp /etc/openvpn/client-common.txt ~/$1.ovpn</span><br><span class="line"> echo &quot;&lt;ca&gt;&quot; &gt;&gt; ~/$1.ovpn</span><br><span class="line"> cat /etc/openvpn/easy-rsa/pki/ca.crt &gt;&gt; ~/$1.ovpn</span><br><span class="line"> echo &quot;&lt;/ca&gt;&quot; &gt;&gt; ~/$1.ovpn</span><br><span class="line"> echo &quot;&lt;cert&gt;&quot; &gt;&gt; ~/$1.ovpn</span><br><span class="line"> cat /etc/openvpn/easy-rsa/pki/issued/$1.crt &gt;&gt; ~/$1.ovpn</span><br><span class="line"> echo &quot;&lt;/cert&gt;&quot; &gt;&gt; ~/$1.ovpn</span><br><span class="line"> echo &quot;&lt;key&gt;&quot; &gt;&gt; ~/$1.ovpn</span><br><span class="line"> cat /etc/openvpn/easy-rsa/pki/private/$1.key &gt;&gt; ~/$1.ovpn</span><br><span class="line"> echo &quot;&lt;/key&gt;&quot; &gt;&gt; ~/$1.ovpn</span><br><span class="line"> echo &quot;&lt;tls-auth&gt;&quot; &gt;&gt; ~/$1.ovpn</span><br><span class="line"> cat /etc/openvpn/ta.key &gt;&gt; ~/$1.ovpn</span><br><span class="line"> echo &quot;&lt;/tls-auth&gt;&quot; &gt;&gt; ~/$1.ovpn</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">if [[ -e /etc/openvpn/server.conf ]]; then</span><br><span class="line"> while :</span><br><span class="line"> do</span><br><span class="line"> clear</span><br><span class="line">  echo &quot;Looks like OpenVPN is already installed.&quot;</span><br><span class="line">  echo</span><br><span class="line">  echo &quot;What do you want to do?&quot;</span><br><span class="line">  echo &quot; 1) Add a new user&quot;</span><br><span class="line">  echo &quot; 2) Revoke an existing user&quot;</span><br><span class="line">  echo &quot; 3) Remove OpenVPN&quot;</span><br><span class="line">  echo &quot; 4) Exit&quot;</span><br><span class="line">  read -p &quot;Select an option [1-4]: &quot; option</span><br><span class="line">  case $option in</span><br><span class="line">   1) </span><br><span class="line">   echo</span><br><span class="line">   echo &quot;Tell me a name for the client certificate.&quot;</span><br><span class="line">   echo &quot;Please, use one word only, no special characters.&quot;</span><br><span class="line">   read -p &quot;Client name: &quot; -e CLIENT</span><br><span class="line">   cd /etc/openvpn/easy-rsa/</span><br><span class="line">   ./easyrsa build-client-full $CLIENT nopass</span><br><span class="line">   # Generates the custom client.ovpn</span><br><span class="line">   newclient &quot;$CLIENT&quot;</span><br><span class="line">   echo</span><br><span class="line">   echo &quot;Client $CLIENT added, configuration is available at:&quot; ~/&quot;$CLIENT.ovpn&quot;</span><br><span class="line">   exit</span><br><span class="line">   ;;</span><br><span class="line">   2)</span><br><span class="line">   # This option could be documented a bit better and maybe even be simplified</span><br><span class="line">   # ...but what can I say, I want some sleep too</span><br><span class="line">   NUMBEROFCLIENTS=$(tail -n +2 /etc/openvpn/easy-rsa/pki/index.txt | grep -c &quot;^V&quot;)</span><br><span class="line">   if [[ &quot;$NUMBEROFCLIENTS&quot; = &apos;0&apos; ]]; then</span><br><span class="line">    echo</span><br><span class="line">    echo &quot;You have no existing clients!&quot;</span><br><span class="line">    exit</span><br><span class="line">   fi</span><br><span class="line">   echo</span><br><span class="line">   echo &quot;Select the existing client certificate you want to revoke:&quot;</span><br><span class="line">   tail -n +2 /etc/openvpn/easy-rsa/pki/index.txt | grep &quot;^V&quot; | cut -d &apos;=&apos; -f 2 | nl -s &apos;) &apos;</span><br><span class="line">   if [[ &quot;$NUMBEROFCLIENTS&quot; = &apos;1&apos; ]]; then</span><br><span class="line">    read -p &quot;Select one client [1]: &quot; CLIENTNUMBER</span><br><span class="line">   else</span><br><span class="line">    read -p &quot;Select one client [1-$NUMBEROFCLIENTS]: &quot; CLIENTNUMBER</span><br><span class="line">   fi</span><br><span class="line">   CLIENT=$(tail -n +2 /etc/openvpn/easy-rsa/pki/index.txt | grep &quot;^V&quot; | cut -d &apos;=&apos; -f 2 | sed -n &quot;$CLIENTNUMBER&quot;p)</span><br><span class="line">   echo</span><br><span class="line">   read -p &quot;Do you really want to revoke access for client $CLIENT? [y/N]: &quot; -e REVOKE</span><br><span class="line">   if [[ &quot;$REVOKE&quot; = &apos;y&apos; || &quot;$REVOKE&quot; = &apos;Y&apos; ]]; then</span><br><span class="line">    cd /etc/openvpn/easy-rsa/</span><br><span class="line">    ./easyrsa --batch revoke $CLIENT</span><br><span class="line">    EASYRSA_CRL_DAYS=3650 ./easyrsa gen-crl</span><br><span class="line">    rm -f pki/reqs/$CLIENT.req</span><br><span class="line">    rm -f pki/private/$CLIENT.key</span><br><span class="line">    rm -f pki/issued/$CLIENT.crt</span><br><span class="line">    rm -f /etc/openvpn/crl.pem</span><br><span class="line">    cp /etc/openvpn/easy-rsa/pki/crl.pem /etc/openvpn/crl.pem</span><br><span class="line">    # CRL is read with each client connection, when OpenVPN is dropped to nobody</span><br><span class="line">    chown nobody:$GROUPNAME /etc/openvpn/crl.pem</span><br><span class="line">    echo</span><br><span class="line">    echo &quot;Certificate for client $CLIENT revoked!&quot;</span><br><span class="line">   else</span><br><span class="line">    echo</span><br><span class="line">    echo &quot;Certificate revocation for client $CLIENT aborted!&quot;</span><br><span class="line">   fi</span><br><span class="line">   exit</span><br><span class="line">   ;;</span><br><span class="line">   3) </span><br><span class="line">   echo</span><br><span class="line">   read -p &quot;Do you really want to remove OpenVPN? [y/N]: &quot; -e REMOVE</span><br><span class="line">   if [[ &quot;$REMOVE&quot; = &apos;y&apos; || &quot;$REMOVE&quot; = &apos;Y&apos; ]]; then</span><br><span class="line">    PORT=$(grep &apos;^port &apos; /etc/openvpn/server.conf | cut -d &quot; &quot; -f 2)</span><br><span class="line">    PROTOCOL=$(grep &apos;^proto &apos; /etc/openvpn/server.conf | cut -d &quot; &quot; -f 2)</span><br><span class="line">    if pgrep firewalld; then</span><br><span class="line">     IP=$(firewall-cmd --direct --get-rules ipv4 nat POSTROUTING | grep &apos;\-s 10.8.0.0/24 &apos;&quot;&apos;&quot;&apos;!&apos;&quot;&apos;&quot;&apos; -d 10.8.0.0/24 -j SNAT --to &apos; | cut -d &quot; &quot; -f 10)</span><br><span class="line">     # Using both permanent and not permanent rules to avoid a firewalld reload.</span><br><span class="line">     firewall-cmd --zone=public --remove-port=$PORT/$PROTOCOL</span><br><span class="line">     firewall-cmd --zone=trusted --remove-source=10.8.0.0/24</span><br><span class="line">     firewall-cmd --permanent --zone=public --remove-port=$PORT/$PROTOCOL</span><br><span class="line">     firewall-cmd --permanent --zone=trusted --remove-source=10.8.0.0/24</span><br><span class="line">     firewall-cmd --direct --remove-rule ipv4 nat POSTROUTING 0 -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j SNAT --to $IP</span><br><span class="line">     firewall-cmd --permanent --direct --remove-rule ipv4 nat POSTROUTING 0 -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j SNAT --to $IP</span><br><span class="line">    else</span><br><span class="line">     IP=$(grep &apos;iptables -t nat -A POSTROUTING -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j SNAT --to &apos; $RCLOCAL | cut -d &quot; &quot; -f 14)</span><br><span class="line">     iptables -t nat -D POSTROUTING -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j SNAT --to $IP</span><br><span class="line">     sed -i &apos;/iptables -t nat -A POSTROUTING -s 10.8.0.0\/24 ! -d 10.8.0.0\/24 -j SNAT --to /d&apos; $RCLOCAL</span><br><span class="line">     if iptables -L -n | grep -qE &apos;^ACCEPT&apos;; then</span><br><span class="line">      iptables -D INPUT -p $PROTOCOL --dport $PORT -j ACCEPT</span><br><span class="line">      iptables -D FORWARD -s 10.8.0.0/24 -j ACCEPT</span><br><span class="line">      iptables -D FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT</span><br><span class="line">      sed -i &quot;/iptables -I INPUT -p $PROTOCOL --dport $PORT -j ACCEPT/d&quot; $RCLOCAL</span><br><span class="line">      sed -i &quot;/iptables -I FORWARD -s 10.8.0.0\/24 -j ACCEPT/d&quot; $RCLOCAL</span><br><span class="line">      sed -i &quot;/iptables -I FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT/d&quot; $RCLOCAL</span><br><span class="line">     fi</span><br><span class="line">    fi</span><br><span class="line">    if sestatus 2&gt;/dev/null | grep &quot;Current mode&quot; | grep -q &quot;enforcing&quot; &amp;&amp; [[ &quot;$PORT&quot; != &apos;1194&apos; ]]; then</span><br><span class="line">     semanage port -d -t openvpn_port_t -p $PROTOCOL $PORT</span><br><span class="line">    fi</span><br><span class="line">    if [[ &quot;$OS&quot; = &apos;debian&apos; ]]; then</span><br><span class="line">     apt-get remove --purge -y openvpn</span><br><span class="line">    else</span><br><span class="line">     yum remove openvpn -y</span><br><span class="line">    fi</span><br><span class="line">    rm -rf /etc/openvpn</span><br><span class="line">    rm -f /etc/sysctl.d/30-openvpn-forward.conf</span><br><span class="line">    echo</span><br><span class="line">    echo &quot;OpenVPN removed!&quot;</span><br><span class="line">   else</span><br><span class="line">    echo</span><br><span class="line">    echo &quot;Removal aborted!&quot;</span><br><span class="line">   fi</span><br><span class="line">   exit</span><br><span class="line">   ;;</span><br><span class="line">   4) exit;;</span><br><span class="line">  esac</span><br><span class="line"> done</span><br><span class="line">else</span><br><span class="line"> clear</span><br><span class="line"> echo &apos;Welcome to this OpenVPN &quot;road warrior&quot; installer!&apos;</span><br><span class="line"> echo</span><br><span class="line"> # OpenVPN setup and first user creation</span><br><span class="line"> echo &quot;I need to ask you a few questions before starting the setup.&quot;</span><br><span class="line"> echo &quot;You can leave the default options and just press enter if you are ok with them.&quot;</span><br><span class="line"> echo</span><br><span class="line"> echo &quot;First, provide the IPv4 address of the network interface you want OpenVPN&quot;</span><br><span class="line"> echo &quot;listening to.&quot;</span><br><span class="line"> # Autodetect IP address and pre-fill for the user</span><br><span class="line"> IP=$(ip addr | grep &apos;inet&apos; | grep -v inet6 | grep -vE &apos;127\.[0-9]&#123;1,3&#125;\.[0-9]&#123;1,3&#125;\.[0-9]&#123;1,3&#125;&apos; | grep -oE &apos;[0-9]&#123;1,3&#125;\.[0-9]&#123;1,3&#125;\.[0-9]&#123;1,3&#125;\.[0-9]&#123;1,3&#125;&apos; | head -1)</span><br><span class="line"> read -p &quot;IP address: &quot; -e -i $IP IP</span><br><span class="line"> # If $IP is a private IP address, the server must be behind NAT</span><br><span class="line"> if echo &quot;$IP&quot; | grep -qE &apos;^(10\.|172\.1[6789]\.|172\.2[0-9]\.|172\.3[01]\.|192\.168)&apos;; then</span><br><span class="line">  echo</span><br><span class="line">  echo &quot;This server is behind NAT. What is the public IPv4 address or hostname?&quot;</span><br><span class="line">  read -p &quot;Public IP address / hostname: &quot; -e PUBLICIP</span><br><span class="line"> fi</span><br><span class="line"> echo</span><br><span class="line"> echo &quot;Which protocol do you want for OpenVPN connections?&quot;</span><br><span class="line"> echo &quot; 1) UDP (recommended)&quot;</span><br><span class="line"> echo &quot; 2) TCP&quot;</span><br><span class="line"> read -p &quot;Protocol [1-2]: &quot; -e -i 1 PROTOCOL</span><br><span class="line"> case $PROTOCOL in</span><br><span class="line">  1) </span><br><span class="line">  PROTOCOL=udp</span><br><span class="line">  ;;</span><br><span class="line">  2) </span><br><span class="line">  PROTOCOL=tcp</span><br><span class="line">  ;;</span><br><span class="line"> esac</span><br><span class="line"> echo</span><br><span class="line"> echo &quot;What port do you want OpenVPN listening to?&quot;</span><br><span class="line"> read -p &quot;Port: &quot; -e -i 1194 PORT</span><br><span class="line"> echo</span><br><span class="line"> echo &quot;Which DNS do you want to use with the VPN?&quot;</span><br><span class="line"> echo &quot; 1) Current system resolvers&quot;</span><br><span class="line"> echo &quot; 2) 1.1.1.1&quot;</span><br><span class="line"> echo &quot; 3) Google&quot;</span><br><span class="line"> echo &quot; 4) OpenDNS&quot;</span><br><span class="line"> echo &quot; 5) Verisign&quot;</span><br><span class="line"> read -p &quot;DNS [1-5]: &quot; -e -i 1 DNS</span><br><span class="line"> echo</span><br><span class="line"> echo &quot;Finally, tell me your name for the client certificate.&quot;</span><br><span class="line"> echo &quot;Please, use one word only, no special characters.&quot;</span><br><span class="line"> read -p &quot;Client name: &quot; -e -i client CLIENT</span><br><span class="line"> echo</span><br><span class="line"> echo &quot;Okay, that was all I needed. We are ready to set up your OpenVPN server now.&quot;</span><br><span class="line"> read -n1 -r -p &quot;Press any key to continue...&quot;</span><br><span class="line"> if [[ &quot;$OS&quot; = &apos;debian&apos; ]]; then</span><br><span class="line">  apt-get update</span><br><span class="line">  apt-get install openvpn iptables openssl ca-certificates -y</span><br><span class="line"> else</span><br><span class="line">  # Else, the distro is CentOS</span><br><span class="line">  yum install epel-release -y</span><br><span class="line">  yum install openvpn iptables openssl ca-certificates -y</span><br><span class="line"> fi</span><br><span class="line"> # Get easy-rsa</span><br><span class="line"> EASYRSAURL=&apos;https://github.com/OpenVPN/easy-rsa/releases/download/v3.0.4/EasyRSA-3.0.4.tgz&apos;</span><br><span class="line"> wget -O ~/easyrsa.tgz &quot;$EASYRSAURL&quot; 2&gt;/dev/null || curl -Lo ~/easyrsa.tgz &quot;$EASYRSAURL&quot;</span><br><span class="line"> tar xzf ~/easyrsa.tgz -C ~/</span><br><span class="line"> mv ~/EasyRSA-3.0.4/ /etc/openvpn/</span><br><span class="line"> mv /etc/openvpn/EasyRSA-3.0.4/ /etc/openvpn/easy-rsa/</span><br><span class="line"> chown -R root:root /etc/openvpn/easy-rsa/</span><br><span class="line"> rm -f ~/easyrsa.tgz</span><br><span class="line"> cd /etc/openvpn/easy-rsa/</span><br><span class="line"> # Create the PKI, set up the CA, the DH params and the server + client certificates</span><br><span class="line"> ./easyrsa init-pki</span><br><span class="line"> ./easyrsa --batch build-ca nopass</span><br><span class="line"> ./easyrsa gen-dh</span><br><span class="line"> ./easyrsa build-server-full server nopass</span><br><span class="line"> ./easyrsa build-client-full $CLIENT nopass</span><br><span class="line"> EASYRSA_CRL_DAYS=3650 ./easyrsa gen-crl</span><br><span class="line"> # Move the stuff we need</span><br><span class="line"> cp pki/ca.crt pki/private/ca.key pki/dh.pem pki/issued/server.crt pki/private/server.key pki/crl.pem /etc/openvpn</span><br><span class="line"> # CRL is read with each client connection, when OpenVPN is dropped to nobody</span><br><span class="line"> chown nobody:$GROUPNAME /etc/openvpn/crl.pem</span><br><span class="line"> # Generate key for tls-auth</span><br><span class="line"> openvpn --genkey --secret /etc/openvpn/ta.key</span><br><span class="line"> # Generate server.conf</span><br><span class="line"> echo &quot;port $PORT</span><br><span class="line">proto $PROTOCOL</span><br><span class="line">dev tun</span><br><span class="line">sndbuf 0</span><br><span class="line">rcvbuf 0</span><br><span class="line">ca ca.crt</span><br><span class="line">cert server.crt</span><br><span class="line">key server.key</span><br><span class="line">dh dh.pem</span><br><span class="line">auth SHA512</span><br><span class="line">tls-auth ta.key 0</span><br><span class="line">topology subnet</span><br><span class="line">server 10.8.0.0 255.255.255.0</span><br><span class="line">ifconfig-pool-persist ipp.txt&quot; &gt; /etc/openvpn/server.conf</span><br><span class="line"> echo &apos;push &quot;redirect-gateway def1 bypass-dhcp&quot;&apos; &gt;&gt; /etc/openvpn/server.conf</span><br><span class="line"> # DNS</span><br><span class="line"> case $DNS in</span><br><span class="line">  1)</span><br><span class="line">  # Locate the proper resolv.conf</span><br><span class="line">  # Needed for systems running systemd-resolved</span><br><span class="line">  if grep -q &quot;127.0.0.53&quot; &quot;/etc/resolv.conf&quot;; then</span><br><span class="line">   RESOLVCONF=&apos;/run/systemd/resolve/resolv.conf&apos;</span><br><span class="line">  else</span><br><span class="line">   RESOLVCONF=&apos;/etc/resolv.conf&apos;</span><br><span class="line">  fi</span><br><span class="line">  # Obtain the resolvers from resolv.conf and use them for OpenVPN</span><br><span class="line">  grep -v &apos;#&apos; $RESOLVCONF | grep &apos;nameserver&apos; | grep -E -o &apos;[0-9]&#123;1,3&#125;\.[0-9]&#123;1,3&#125;\.[0-9]&#123;1,3&#125;\.[0-9]&#123;1,3&#125;&apos; | while read line; do</span><br><span class="line">   echo &quot;push \&quot;dhcp-option DNS $line\&quot;&quot; &gt;&gt; /etc/openvpn/server.conf</span><br><span class="line">  done</span><br><span class="line">  ;;</span><br><span class="line">  2)</span><br><span class="line">  echo &apos;push &quot;dhcp-option DNS 1.1.1.1&quot;&apos; &gt;&gt; /etc/openvpn/server.conf</span><br><span class="line">  echo &apos;push &quot;dhcp-option DNS 1.0.0.1&quot;&apos; &gt;&gt; /etc/openvpn/server.conf</span><br><span class="line">  ;;</span><br><span class="line">  3)</span><br><span class="line">  echo &apos;push &quot;dhcp-option DNS 8.8.8.8&quot;&apos; &gt;&gt; /etc/openvpn/server.conf</span><br><span class="line">  echo &apos;push &quot;dhcp-option DNS 8.8.4.4&quot;&apos; &gt;&gt; /etc/openvpn/server.conf</span><br><span class="line">  ;;</span><br><span class="line">  4)</span><br><span class="line">  echo &apos;push &quot;dhcp-option DNS 208.67.222.222&quot;&apos; &gt;&gt; /etc/openvpn/server.conf</span><br><span class="line">  echo &apos;push &quot;dhcp-option DNS 208.67.220.220&quot;&apos; &gt;&gt; /etc/openvpn/server.conf</span><br><span class="line">  ;;</span><br><span class="line">  5)</span><br><span class="line">  echo &apos;push &quot;dhcp-option DNS 64.6.64.6&quot;&apos; &gt;&gt; /etc/openvpn/server.conf</span><br><span class="line">  echo &apos;push &quot;dhcp-option DNS 64.6.65.6&quot;&apos; &gt;&gt; /etc/openvpn/server.conf</span><br><span class="line">  ;;</span><br><span class="line"> esac</span><br><span class="line"> echo &quot;keepalive 10 120</span><br><span class="line">cipher AES-256-CBC</span><br><span class="line">user nobody</span><br><span class="line">group $GROUPNAME</span><br><span class="line">persist-key</span><br><span class="line">persist-tun</span><br><span class="line">status openvpn-status.log</span><br><span class="line">verb 3</span><br><span class="line">crl-verify crl.pem&quot; &gt;&gt; /etc/openvpn/server.conf</span><br><span class="line"> # Enable net.ipv4.ip_forward for the system</span><br><span class="line"> echo &apos;net.ipv4.ip_forward=1&apos; &gt; /etc/sysctl.d/30-openvpn-forward.conf</span><br><span class="line"> # Enable without waiting for a reboot or service restart</span><br><span class="line"> echo 1 &gt; /proc/sys/net/ipv4/ip_forward</span><br><span class="line"> if pgrep firewalld; then</span><br><span class="line">  # Using both permanent and not permanent rules to avoid a firewalld</span><br><span class="line">  # reload.</span><br><span class="line">  # We don&apos;t use --add-service=openvpn because that would only work with</span><br><span class="line">  # the default port and protocol.</span><br><span class="line">  firewall-cmd --zone=public --add-port=$PORT/$PROTOCOL</span><br><span class="line">  firewall-cmd --zone=trusted --add-source=10.8.0.0/24</span><br><span class="line">  firewall-cmd --permanent --zone=public --add-port=$PORT/$PROTOCOL</span><br><span class="line">  firewall-cmd --permanent --zone=trusted --add-source=10.8.0.0/24</span><br><span class="line">  # Set NAT for the VPN subnet</span><br><span class="line">  firewall-cmd --direct --add-rule ipv4 nat POSTROUTING 0 -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j SNAT --to $IP</span><br><span class="line">  firewall-cmd --permanent --direct --add-rule ipv4 nat POSTROUTING 0 -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j SNAT --to $IP</span><br><span class="line"> else</span><br><span class="line">  # Needed to use rc.local with some systemd distros</span><br><span class="line">  if [[ &quot;$OS&quot; = &apos;debian&apos; &amp;&amp; ! -e $RCLOCAL ]]; then</span><br><span class="line">   echo &apos;#!/bin/sh -e</span><br><span class="line">exit 0&apos; &gt; $RCLOCAL</span><br><span class="line">  fi</span><br><span class="line">  chmod +x $RCLOCAL</span><br><span class="line">  # Set NAT for the VPN subnet</span><br><span class="line">  iptables -t nat -A POSTROUTING -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j SNAT --to $IP</span><br><span class="line">  sed -i &quot;1 a\iptables -t nat -A POSTROUTING -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j SNAT --to $IP&quot; $RCLOCAL</span><br><span class="line">  if iptables -L -n | grep -qE &apos;^(REJECT|DROP)&apos;; then</span><br><span class="line">   # If iptables has at least one REJECT rule, we asume this is needed.</span><br><span class="line">   # Not the best approach but I can&apos;t think of other and this shouldn&apos;t</span><br><span class="line">   # cause problems.</span><br><span class="line">   iptables -I INPUT -p $PROTOCOL --dport $PORT -j ACCEPT</span><br><span class="line">   iptables -I FORWARD -s 10.8.0.0/24 -j ACCEPT</span><br><span class="line">   iptables -I FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT</span><br><span class="line">   sed -i &quot;1 a\iptables -I INPUT -p $PROTOCOL --dport $PORT -j ACCEPT&quot; $RCLOCAL</span><br><span class="line">   sed -i &quot;1 a\iptables -I FORWARD -s 10.8.0.0/24 -j ACCEPT&quot; $RCLOCAL</span><br><span class="line">   sed -i &quot;1 a\iptables -I FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT&quot; $RCLOCAL</span><br><span class="line">  fi</span><br><span class="line"> fi</span><br><span class="line"> # If SELinux is enabled and a custom port was selected, we need this</span><br><span class="line"> if sestatus 2&gt;/dev/null | grep &quot;Current mode&quot; | grep -q &quot;enforcing&quot; &amp;&amp; [[ &quot;$PORT&quot; != &apos;1194&apos; ]]; then</span><br><span class="line">  # Install semanage if not already present</span><br><span class="line">  if ! hash semanage 2&gt;/dev/null; then</span><br><span class="line">   yum install policycoreutils-python -y</span><br><span class="line">  fi</span><br><span class="line">  semanage port -a -t openvpn_port_t -p $PROTOCOL $PORT</span><br><span class="line"> fi</span><br><span class="line"> # And finally, restart OpenVPN</span><br><span class="line"> if [[ &quot;$OS&quot; = &apos;debian&apos; ]]; then</span><br><span class="line">  # Little hack to check for systemd</span><br><span class="line">  if pgrep systemd-journal; then</span><br><span class="line">   systemctl restart openvpn@server.service</span><br><span class="line">  else</span><br><span class="line">   /etc/init.d/openvpn restart</span><br><span class="line">  fi</span><br><span class="line"> else</span><br><span class="line">  if pgrep systemd-journal; then</span><br><span class="line">   systemctl restart openvpn@server.service</span><br><span class="line">   systemctl enable openvpn@server.service</span><br><span class="line">  else</span><br><span class="line">   service openvpn restart</span><br><span class="line">   chkconfig openvpn on</span><br><span class="line">  fi</span><br><span class="line"> fi</span><br><span class="line"> # If the server is behind a NAT, use the correct IP address</span><br><span class="line"> if [[ &quot;$PUBLICIP&quot; != &quot;&quot; ]]; then</span><br><span class="line">  IP=$PUBLICIP</span><br><span class="line"> fi</span><br><span class="line"> # client-common.txt is created so we have a template to add further users later</span><br><span class="line"> echo &quot;client</span><br><span class="line">dev tun</span><br><span class="line">proto $PROTOCOL</span><br><span class="line">sndbuf 0</span><br><span class="line">rcvbuf 0</span><br><span class="line">remote $IP $PORT</span><br><span class="line">resolv-retry infinite</span><br><span class="line">nobind</span><br><span class="line">persist-key</span><br><span class="line">persist-tun</span><br><span class="line">remote-cert-tls server</span><br><span class="line">auth SHA512</span><br><span class="line">cipher AES-256-CBC</span><br><span class="line">setenv opt block-outside-dns</span><br><span class="line">key-direction 1</span><br><span class="line">verb 3&quot; &gt; /etc/openvpn/client-common.txt</span><br><span class="line"> # Generates the custom client.ovpn</span><br><span class="line"> newclient &quot;$CLIENT&quot;</span><br><span class="line"> echo</span><br><span class="line"> echo &quot;Finished!&quot;</span><br><span class="line"> echo</span><br><span class="line"> echo &quot;Your client configuration is available at:&quot; ~/&quot;$CLIENT.ovpn&quot;</span><br><span class="line"> echo &quot;If you want to add more clients, you simply need to run this script again!&quot;</span><br><span class="line">fi</span><br></pre></td></tr></table></figure>
</section>
    <!-- Tags START -->
    
    <!-- Tags END -->
    <!-- NAV START -->
    
  <div class="nav-container">
    <!-- reverse left and right to put prev and next in a more logic postition -->
    
      <a class="nav-left" href="/blog/2018/09/09/mysqlfenku-bak-sh/">
        <span class="nav-arrow">← </span>
        
          mysqlfenku_bak.sh
        
      </a>
    
    
      <a class="nav-right" href="/blog/2018/09/09/rsyncd-sh/">
        
          rsyncd.sh
        
        <span class="nav-arrow"> →</span>
      </a>
    
  </div>

    <!-- NAV END -->
    
      <!-- No Comment -->
    
  </article>
  <!-- Article END -->
  <!-- Catalog START -->
  
    <aside class="catalog-container">
  <div class="toc-main">
    <strong class="toc-title">Catalog</strong>
    
      <ol class="nav">none</ol>
    
  </div>
</aside>
  
  <!-- Catalog END -->
</main>

<script>
  (function () {
    var url = 'git@gitee.com:sanyuanempire/blog.git/2018/09/09/openvpn-install-sh/';
    var banner = ''
    if (banner !== '' && banner !== 'undefined' && banner !== 'null') {
      $('#article-banner').css({
        'background-image': 'url(' + banner + ')'
      })
    } else {
      $('#article-banner').geopattern(url)
    }
    $('.header').removeClass('fixed-header')

     // error image
    $(".markdown-content img").on('error', function() {
      $(this).attr('src', 'http://file.muyutech.com/error-img.png')
      $(this).css({
        'cursor': 'default'
      })
    })

    // zoom image
    $(".markdown-content img").on('click', function() {
      var src = $(this).attr('src')
      if (src !== 'http://file.muyutech.com/error-img.png') {
        var imageW = $(this).width()
        var imageH = $(this).height()
        
        var zoom = ($(window).width() * 0.95 / imageW).toFixed(2)
        zoom = zoom < 1 ? 1 : zoom
        zoom = zoom > 2 ? 2 : zoom
        var transY = (($(window).height() - imageH) / 2).toFixed(2)

        $('body').append('<div class="image-view-wrap"><div class="image-view-inner"><img src="'+ src +'" /></div></div>')
        $('.image-view-wrap').addClass('wrap-active')
        $('.image-view-wrap img').css({
          'width': `${imageW}`,
          'transform': `translate3d(0, ${transY}px, 0) scale3d(${zoom}, ${zoom}, 1)`
        })
        $('html').css('overflow', 'hidden')

        $('.image-view-wrap').on('click', function() {
          $(this).remove()
          $('html').attr('style', '')
        })
      }
    })

    // qrcode
    var qr = new QRious({
      element: document.getElementById('share-qrcode'),
      value: document.location.href
    });

    // gitment
    var gitmentConfig = "";
    if (gitmentConfig !== 'undefined') {
      var gitment = new Gitment({
        id: "openvpn-install.sh",
        owner: "",
        repo: "",
        oauth: {
          client_id: "",
          client_secret: ""
        },
        theme: {
          render(state, instance) {
            const container = document.createElement('div')
            container.lang = "en-US"
            container.className = 'gitment-container gitment-root-container'
            container.appendChild(instance.renderHeader(state, instance))
            container.appendChild(instance.renderEditor(state, instance))
            container.appendChild(instance.renderComments(state, instance))
            container.appendChild(instance.renderFooter(state, instance))
            return container;
          }
        }
      })
      gitment.render(document.getElementById('comments'))
    }
  })();
</script>

<script>
  var disqus_shortname = '';
  
  var disqus_url = 'git@gitee.com:sanyuanempire/blog.git/2018/09/09/openvpn-install-sh/';
  
  (function(){
    var dsq = document.createElement('script');
    dsq.type = 'text/javascript';
    dsq.async = true;
    dsq.src = '//go.disqus.com/embed.js';
    (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
  })();
</script>

    <div class="scroll-top">
  <span class="arrow-icon"></span>
</div>
    <footer class="app-footer">
  <p class="copyright">
    &copy; 2018 | Proudly powered by <a href="https://sanyuanempire.gitee.io/blog" target="_blank">JinYan</a>
    <br>
    Theme by <a href="https://sanyuanempire.gitee.io/blog">JinYan</a>
  </p>
</footer>

<script>
  function async(u, c) {
    var d = document, t = 'script',
      o = d.createElement(t),
      s = d.getElementsByTagName(t)[0];
    o.src = u;
    if (c) { o.addEventListener('load', function (e) { c(null, e); }, false); }
    s.parentNode.insertBefore(o, s);
  }
</script>
<script>
  async("//cdn.bootcss.com/fastclick/1.0.6/fastclick.min.js", function(){
    FastClick.attach(document.body);
  })
</script>

<script>
  var hasLine = 'true';
  async("//cdn.bootcss.com/highlight.js/9.12.0/highlight.min.js", function(){
    $('figure pre').each(function(i, block) {
      var figure = $(this).parents('figure');
      if (hasLine === 'false') {
        figure.find('.gutter').hide();
      }
      var lang = figure.attr('class').split(' ')[1] || 'code';
      var codeHtml = $(this).html();
      var codeTag = document.createElement('code');
      codeTag.className = lang;
      codeTag.innerHTML = codeHtml;
      $(this).attr('class', '').empty().html(codeTag);
      figure.attr('data-lang', lang.toUpperCase());
      hljs.highlightBlock(block);
    });
  })
</script>
<!-- Baidu Tongji -->

<script src="/blog/js/script.js"></script>

  </body>
</html>